package com.neusoft.databus.core.metric;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.stereotype.Component;

import com.neusoft.databus.common.bean.CommandBean;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@Endpoint(id = "tps")
public class TpsEndpoint {
    private final long start = System.currentTimeMillis();
    private long last = -1;
    private final AtomicInteger countOfInterval = new AtomicInteger(0);
    private final AtomicInteger countOfTotal = new AtomicInteger(0);
    private final Map<String, Object> map = new HashMap<>();

    @Value("${databus.core.tpsFrequency:3000}")
    private int frequency;

    @ReadOperation
    public Map<String, Object> endpoint() {
        if (this.map.isEmpty()) {
            this.map.put("start", this.start);
        }
        return this.map;
    }

    public void saveLatestTps(List<CommandBean> commandResults) {
        commandResults.forEach(c -> {
            this.saveLatestTps(c);
        });
    }

    public void saveLatestTps(CommandBean commandResult) {
        try {
            final long currentTimeMillis = System.currentTimeMillis();
            if (this.last == -1) {
                this.last = currentTimeMillis;
            }

            final int count = commandResult.getResourceBean().stream()
                    .mapToInt(it -> it.getMetrics().stream().mapToInt(m -> {
                        return m.isParseSuccess() ? 1 : 0;
                    }).sum()).sum();
            this.countOfInterval.getAndAdd(count);
            this.countOfTotal.getAndAdd(count);

            if ((currentTimeMillis - this.last) >= this.frequency) {
                this.map.put("time", currentTimeMillis);
                this.map.put("tps", (this.countOfInterval.get() * 1000) / (currentTimeMillis - this.last));
                this.map.put("total", this.countOfTotal.get());
                this.last = currentTimeMillis;
                this.countOfInterval.getAndSet(0);
            }
        } catch (final Throwable e) {
            TpsEndpoint.log.error(e.getMessage(), e);
        }
    }
}
